S16-00 专题-Node-Monorepo
[TOC]
索引【
Monorepo
概述
Monorepo(单一代码仓库):是一种软件开发策略,指将多个相关项目的代码存储在一个统一的版本控制仓库中(而不是为每个项目单独创建仓库)。与之相对的是传统的 Multirepo(多仓库) 模式。
Monorepo 目录中除了会有公共的package.json
依赖以外,在每个sub-package
子包下面,也会有其特有的package.json
依赖。
兄弟模块之间可以通过模块 package.json
定义的 name
相互引用,保证模块之间的独立性
# monorepo目录结构
monorepo-demo
├── packages
│ ├─ module-a
│ │ ├─ src # 模块 a 的源码
│ │ ├─ node_modules # 模块 a 的 node_modules
│ │ └─ package.json # 仅模块 a 的依赖
│ └─ module-b
│ ├─ src # 模块 b 的源码
│ └─ package.json # 仅模块 b 的依赖
├── .eslintrc # 配置文件,对整个项目生效
├── node_modules # 所有子包公共的 node_modules
└── package.json # 所有子包公共的依赖
Multirepo(多仓库):更倾向与在项目制中,将一个个项目使用不同的仓库进行隔离,每一个项目下使用独有的package.json
来管理依赖
# multirepo-a目录结构
multirepo-a
├── src
├── .eslintrc
├── node_modules
└── package.json
# multirepo-b目录结构
multirepo-b
├── src
├── .eslintrc
├── node_modules
└── package.json
Monorepo 工具
Monorepo 工具:
在采用 Monorepo(单一仓库)架构的软件开发中,工具的选择是至关重要的。合适的 Monorepo 工具能够帮助团队更高效地管理大规模代码库、提升协同开发体验以及优化构建和部署流程。
直至 2024 年,目前在前端界比较流行的 Monorepo 工具有:
Pnpm Workspaces
(推荐)Yarn Workspaces
npm Workspaces
Rush
Turborepo
Lerna
Yalc
Nx
强烈推荐使用 Pnpm Workspaces
作为 Monorepo 项目的依赖管理工具。pnpm 安装包速度快,磁盘空间利用率高。
Monorepo vs 包管理工具
Monorepo和包管理工具的关系:
那么 Monorepo 与包管理工具(npm、yarn、pnpm)之间是一种怎样的关系?
这些包管理工具与 monorepo 的关系在于,它们可以为 monorepo 提供依赖安装与依赖管理的支持,借助自身对 workspace 的支持,允许在 monorepo 中的不同子项目之间共享依赖项,并提供一种管理这些共享依赖项的方式,这可以简化依赖项管理和构建过程,并提高开发效率。
Monorepo 项目搭建@
背景
传统的多仓库 Multirepo 模式,通常都是一个仓库存放一个项目。比如现在你有三个项目,就需要创建三个远程仓库,并且需要为每个项目单独安装和升级依赖。
而单一仓库 Monorepo 模式,就是在一个仓库中管理多个项目,这些项目可以是独立的,也可以相互依赖。通过 Monorepo,多个项目可以共享依赖。比如多个项目都需要 lodash
,那我们也只需安装一次即可。
pnpm i lodash -w
当然,Monorepo 中除了公共的package.json
依赖以外,在每个sub-package
子包下面,也会有其私有的package.json
依赖。
我们本次选择Pnpm Workspaces
作为 Monorepo 项目的依赖管理工具,一起来搭建一个 monorepo
项目。
安装包管理工具
全局安装 pnpm
npm i pnpm -g
初始化项目
1、创建一个新的项目目录 pnpm-monorepo
。
2、根目录运行 pnpm init
创建 package.json
文件。
3、然后根目录新建一个文件夹 packages
,用于存储子包。
共享包:
4、新建 packages/libc-shared
( 共享包 ),用于存放多个项目或组件之间共享的代码 。
5、运行 pnpm init
创建 package.json
文件。
- 修改
package.json
的 name 为"@libc/shared"
; - 修改
package.json
的 main 入口文件路径字段为"src/index.js"
{
"name": "@libc/shared",
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
}
公共组件包:
6、新建 packages/libc-ui
( 公共组件包 ),即UI组件库,这里我们直接 clone 了 iview-ui-plus 代码。
7、运行 pnpm install
安装依赖。
- 修改
package.json
的 name 为"@libc/ui"
; - 修改
package.json
的 main 入口文件路径字段为"src/index.js"
vue 项目:
8、然后我们在 packages
下创建两个 vue 项目,vue-dom1
和 vue-dom2
,运行脚本pnpm create vue@latest
。
9、由于两个项目的依赖是完全一样的,我们可以将 dependencies
、devDependencies
复制到外层 package.json
中当做公共依赖,然后pnpm install
安装一次即可。
配置 workspace:
10、到了这一步,vue 项目还是不能运行,必须要先配置 workspace,用于支持多包存储库。让子包 vue 项目可以访问到我们的公共依赖。
配置 workspace
1、根目录新建一个 pnpm-workspace.yaml
,将 packages 下所有的直接子目录都作为包进行管理。
packages:
# all packages in direct subdirs of packages/
- 'packages/*' # * 是glob语法
2、pnpm-monorepo
最终项目结构
pnpm-monorepo/
├── packages/
│ ├── libc-shared/
│ ├── libc-ui/
│ ├── vue-dome1/
│ └── vue-dome2/
├── package.json
└── pnpm-workspace.yaml
子包共享
子包之间共享:
此时,pnpm-workspace.yaml
工作空间下的每个子包都可以共享我们的公共依赖了。还有个问题是,兄弟模块之间如何共享呢? 之前我们说过,子包之间可以通过 package.json
定义的 name
相互引用,一起看下两个实际场景。
如何把子包 libc-shared 共享出去?
1、用--workspace
参数去安装共享子包,会去 workspace工作空间中找依赖项并安装。
pnpm install @libc/shared --workspace -w
2、根目录的package.json
中就会自动添加如下依赖:
"workspace:"
只会解析本地 workspace 包含的 package。"workspace:*"
表示可以使用任意版本。
"dependencies": {
"@libc/shared": "workspace:^"
}
3、此时,vue 项目就可以使用公共包 libc-shared
里的方法,import 引入即可。
import { isObject } from '@libc/shared'
如何把子包 libc-ui 共享出去?
1、重复一下上面的步骤,然后我们去引用一个 button
组件。
2、问题:引用一个 button
组件时发现报错了:
Failed to resolve import "./base" from "../libc-ui/src/components/typography/title.vue". Does the file exist?
解决:vite.config.js
中添加 extensions
即可解决,配置一下省略的扩展名列表。
resolve: {
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
}
2、虽然 button
组件引用成功了,但是发现没有任何样式效果。在libc-ui/src/index.js
文件中导入一下样式文件就行了。
import "./styles/index.less";
公共依赖
1、全局安装公共依赖 lodash
。需要加-w
(在工作空间的根目录中启动 pnpm)。
pnpm install lodash -w
2、这样,vue-dom1
和 vue-dom2
这两个 vue项目就都可以使用 lodash
库了。
局部依赖
1、如果只有 vue-dom1
项目用到了 lodash
,我们也可以安装到vue-dom1
项目内部,不作为公共依赖项,有两种方法可以实现:
- 方法一:cd 到
src/packages/vue-dom1
目录下,直接安装。
pnpm install lodash
- 方法二:在任意目录下,使用
--filter
参数进行安装。
pnpm install lodash --filter vue-demo1